<template>
<div>
    <header class="header">
        <div class="header-content">
            <div class="header-left">
                <a href="#" @click="GoBack()" class="back-btn">
                    <svg t="1751614585251" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" 
                        p-id="1471" width="20" height="20">
                        <path d="M790.865959 73.216062 322.123178 512.062492l468.74278 438.746442c16.397998 16.697962 16.397998 43.894642 0 60.592603-16.397998 16.697962-42.894764 16.697962-59.292762 0l-498.839107-466.943c-8.698938-8.898914-12.398487-20.797461-11.898548-32.496033-0.599927-11.698572 3.099622-23.497132 11.898548-32.496033l498.839107-466.943c16.397998-16.697962 42.894764-16.697962 59.292762 0C807.263957 29.421409 807.263957 56.518101 790.865959 73.216062z" 
                            fill="#272636" 
                            p-id="1472">
                        </path>
                    </svg>
                </a>
                <div class="header-title">发布内容</div>
            </div>
            <button class="publish-btn" @click="publishPost()" v-loading.fullscreen.lock="fullscreenLoading">发布</button>
        </div>
    </header>

    <main class="main-content">
        <div class="publish-form">
            <!--标题-->
            <div class="form-group">
                <label class="form-label">标题</label>
                <input v-model="postAddOrUpdateDTO.title" type="text" class="title-input" placeholder="给你的分享起个标题吧..." maxlength="50">
                <div class="error-message" v-if="titleError">{{ titleError }}</div>
                <div :class="['char-count', { warning: isNearLimit_text }]">
                    {{ textCharCount }}/50
                </div>
            </div>
           
            <!--内容-->
            <div class="form-group">
                <label class="form-label">内容</label>
                <textarea v-model="postAddOrUpdateDTO.content" class="content-textarea" placeholder="分享你的生活，记录美好时光..." maxlength="1000"></textarea>
                <div class="error-message" v-if="contentError">{{ contentError }}</div>
                <div :class="['char-count', { warning: isNearLimit_textarea }]">
                    {{ textareaCharCount }}/1000
                </div>
            </div>
            
            <!--图片-->
            <div class="form-group">
                <label class="form-label">添加图片</label>

                <el-upload ref="picUploadRef"
                    v-model:file-list="fileList"
                    :action= "path.baseUrl + '/common/file/upload'"
                    list-type="picture-card"
                    accept="image/*"
                    name="file"
                    :auto-upload="true"
                    :headers="UploadHeaders"
                    :data="UploadData"
                    :limit="9"
                    :before-upload="beforeUpload"
                    :on-exceed="handleExceed"
                    :on-success="handleUploadSuccess"
                    :on-preview="handlePictureCardPreview"
                    :on-remove="handleRemove"
                >
                    <el-icon><Plus /></el-icon>
                    <template #tip>
                        <div class="el-upload__tip">单张图片请勿超过2MB</div>
                    </template>

                    <template #file="{ file }">
                        <div>
                            <img class="el-upload-list__item-thumbnail" :src="file.url" alt="" />
                            <span class="el-upload-list__item-actions">
                                <span class="el-upload-list__item-preview" @click="handlePictureCardPreview(file)">
                                    <el-icon><zoom-in /></el-icon>
                                </span>
                                <span class="el-upload-list__item-delete" @click="handleRemove(file, null)">
                                    <el-icon><Delete /></el-icon>
                                </span>
                            </span>
                        </div>
                    </template>

                </el-upload>
                <el-image-viewer
                    v-if="showPreview"
                    :url-list="postAddOrUpdateDTO.imageUrlList"
                    show-progress
                    :initial-index="1"
                    @close="showPreview = false"
                />
            </div>
            
            <!--标签-->
            <div class="form-group">
                <label class="form-label">添加标签</label>
                <el-select v-model="postAddOrUpdateDTO.tagIdList" multiple clearable placeholder="请选择" style="width: 100%;">
                    <el-option v-for="item in tag_Store.tagList" :key="item.id" :label="item.name" :value="item.id"/>
                    <template #tag>
                        <el-tag v-for="id in postAddOrUpdateDTO.tagIdList" :key="id" effect="dark" color="#ff6b6b" closable @close="handleClose(id)">
                            {{ tagNameMap[id] }}
                        </el-tag>
                    </template>
                </el-select>
                <div class="error-message" v-if="tagError">{{ tagError }}</div>
            </div>
            
            <!--话题-->
            <div class="form-group">
                <label class="form-label">选择话题（可选，最多2个）</label>
                <el-select
                    v-model="postAddOrUpdateDTO.topicIdList"
                    multiple
                    filterable
                    reserve-keyword
                    :multiple-limit=2
                    :loading="topicLoading"
                    @focus="handleTopicFocus()"
                    @visible-change="visibleChange"
                    placeholder="请选择"
                    style="width: 100%"
                >
                    <el-option
                        v-for="item in topicOptions"
                        :key="item.id"
                        :label="'#' + item.name"
                        :value="item.id"
                    />
                    <template #loading>
                        <svg class="circular" viewBox="0 0 50 50">
                            <circle class="path" cx="25" cy="25" r="20" fill="none" />
                        </svg>
                    </template>
                    <template #footer>
                        <span v-if="topicScrollLoading && topicScrollHasMore">加载中...</span>
                        <span v-else-if="!topicScrollLoading && !topicScrollHasMore">没有更多相关话题</span>
                    </template>
                </el-select>
            </div>
            
            <!--隐私设置-->
            <div class="form-group">
                <label class="form-label">隐私设置</label>
                <div class="privacy-options">
                    <div class="privacy-option" @click="postAddOrUpdateDTO.privacy = 1">
                        <div class="privacy-radio" :class="{ checked: postAddOrUpdateDTO.privacy == 1}"></div>
                        <span>公开</span>
                    </div>
                    <div class="privacy-option" @click="postAddOrUpdateDTO.privacy = 2">
                        <div class="privacy-radio" :class="{ checked: postAddOrUpdateDTO.privacy == 2}"></div>
                        <span>仅朋友可见</span>
                    </div>
                    <div class="privacy-option" @click="postAddOrUpdateDTO.privacy = 3">
                        <div class="privacy-radio" :class="{ checked: postAddOrUpdateDTO.privacy == 3}"></div>
                        <span>仅自己可见</span>
                    </div>
                </div>
            </div>
            
            <!--操作-->
            <div class="form-actions">
                <div @click="save()" class="btn-secondary">保存</div>
                <div class="btn-primary" @click="publishPost()" v-loading.fullscreen.lock="fullscreenLoading">发布</div>
            </div>
        </div>
    </main>

</div>
</template>

<script lang="ts" setup>
import { ref, onMounted ,computed } from 'vue'
import { useRouter } from 'vue-router'
import { Plus, Delete, ZoomIn } from '@element-plus/icons-vue'
import type { UploadInstance, UploadProps, UploadFile, UploadFiles } from 'element-plus'
import api from '@/api/index'
import path from '@/api/path'
import { deep_cp_Func } from '@/utils/copyProperties'
import { CacheComponentStore } from '@/stores/cache/cacheComponentStore'
import { UserInfoStore } from '@/stores/userInfoStore'
import { TagStore } from '@/stores/tagStore'
import { TipStore } from '@/stores/tipStore'

const router = useRouter()
const cache_Store = CacheComponentStore()
const user_Store = UserInfoStore()
const tag_Store = TagStore()
const tip_Store = TipStore()


// #region 公用数据
const addOrEditFlag = ref('')
const postAddOrUpdateDTO = ref({
    id: null,
    userId: user_Store.userInfo?.id,
    title: null,
    content: null,
    privacy: 1,
    location: null,

    imageUrlList: [],
    tagIdList: [],
    topicIdList: [],
})

// 错误信息
const titleError = ref('')
const contentError = ref('')
const tagError = ref('')

const fullscreenLoading = ref(false) // 全屏加载标识
// #endregion


// #region 公用方法
// 返回
function GoBack() {
    router.go(-1)
}

// 编辑状态下要准备的操作
const editPrepareOperation = async() => {
    // 1.根据传过来的id查询帖子
    const postRes = await api.Post_GetById(postId_edit)
    deep_cp_Func(postRes.data.data, postAddOrUpdateDTO.value) // 将属性拷贝进postAddOrUpdateDTO里面
    
    // 2.将图片URL转换为el-upload需要的文件列表格式
    if (Array.isArray(postAddOrUpdateDTO.value.imageUrlList)) {
        
        fileList.value = postAddOrUpdateDTO.value.imageUrlList.map(url => ({
            name: url.substring(url.lastIndexOf('/') + 1),
            url: url,
            response: { data: url }
        }))
    } else {
        fileList.value = []
    }
    console.log(postAddOrUpdateDTO.value)

    // 3.根据话题id查询话题
    if(postAddOrUpdateDTO.value.topicIdList && postAddOrUpdateDTO.value.topicIdList.length > 0){
        api.Topic_GetByIds(postAddOrUpdateDTO.value.topicIdList).then(res =>{
            topicOptions.value.push(...res.data.data) // 将本就有的话题对象添加进去，否则选择框无法显示对应的标签，只会显示id
        })
    }
}
// #endregion


// #region 字符计数
// 标题
const textCharCount = computed(() => {
    if(postAddOrUpdateDTO.value.title == null){
        return 0
    }else{
        return postAddOrUpdateDTO.value.title.length
    }
});
const isNearLimit_text = computed(() => textCharCount.value > 45);

// 内容
const textareaCharCount = computed(() => {
    if(postAddOrUpdateDTO.value.content == null){
        return 0
    }else{
        return postAddOrUpdateDTO.value.content.length
    }
});
const isNearLimit_textarea = computed(() => textareaCharCount.value > 1000);
// #endregion


// #region 上传图片
const picUploadRef = ref<UploadInstance>()
const fileList = ref([]) // 图片列表（本质上是本地的文件），用于在上传组件中展示图片
const showPreview = ref(false)

const UploadHeaders = ref({ // 上传时附带的请求头
  [user_Store.userJwtToken]: localStorage.getItem(user_Store.userToken) // 请求头名字，使用计算属性名，避免硬编码
})
const UploadData = ref({ // 上传时附带的额外参数
  userId: user_Store.userInfo?.id,
})
// 手动上传文件
const submitUpload = () => {
  picUploadRef.value!.submit()
}

const handleExceed: UploadProps['onExceed'] = (files, uploadFiles) => {
    tip_Store.warningTip('最多上传9张图片')
}

// 文件上传前触发
const beforeUpload: UploadProps['beforeUpload'] = (rawFile) => {
    if (!rawFile.type.startsWith('image/')) {
        tip_Store.errorTip('文件必须为图片格式!')
        return false
    } else if (rawFile.size / 1024 / 1024 > 2) {
        tip_Store.errorTip('封面大小不能超过 2MB!')
        return false
    }
    return true
}

// 上传成功，获取返回的图片地址
const handleUploadSuccess = (response: any, uploadFile: UploadFile, uploadFiles: UploadFiles) => {
    console.log("图片上传成功：",response)
    // 如果是数组
    if (Array.isArray(response.data)) {
        postAddOrUpdateDTO.value.imageUrlList.push(...response.data)
    }else{
        postAddOrUpdateDTO.value.imageUrlList.push(response.data)
    }
    console.log("准备存储在云存储的图片地址列表：", postAddOrUpdateDTO.value.imageUrlList)
}

// 图片移除
const handleRemove: UploadProps['onRemove'] = async (uploadFile: UploadFile, uploadFiles: UploadFiles) => {

    console.log("移除图片触发函数：",uploadFile)
    console.log("要删除图片的url（本地的）：", uploadFile.url)
    console.log("要删除图片的url（远程存储的）：", (uploadFile.response as any)?.data)

    try{
        // 1、删除云存储中的图片
        const fileFullPath = (uploadFile.response as any)?.data
        const DelRes = await api.fileDelete(fileFullPath)
        if(DelRes.data.code != 1){
            tip_Store.errorTip()
            return;
        }

        let index = fileList.value.indexOf(uploadFile)
        if (index === -1) {
            tip_Store.errorTip('未找到待删除文件')
            throw new Error('未找到待删除文件');
        }

        // 2、在前端列表中移除
        fileList.value.splice(index, 1)

        // 3、从准备发送的DTO实体中删除
        postAddOrUpdateDTO.value.imageUrlList.splice(index, 1)

        tip_Store.successTip()

    }catch(err){
        alert("删除失败，请稍后再试")
    }
    
    
}

// 图片预览
const handlePictureCardPreview: UploadProps['onPreview'] = (uploadFile) => {
    showPreview.value = true
}

// #endregion


// #region 标签相关
// 删除标签
const handleClose = (id) => {
  postAddOrUpdateDTO.value.tagIdList.splice(postAddOrUpdateDTO.value.tagIdList.indexOf(id), 1)
}
// 标签名称映射
const tagNameMap = computed(() => {
  const map = {}
  tag_Store.tagList.forEach(tag => {
    map[tag.id] = tag.name
  })
  return map
})
// #endregion


// #region 话题相关
const topicLoading = ref(false)
const topicOptions = ref([]) // 用于选择的话题列表
// 分页
const current_Topic = ref(1)
const size_Topic = ref(10)

// 分页获取话题
const loadTopic = async()=>{
    const res = await api.Topic_GetAllByPage(current_Topic.value, size_Topic.value)
    const newTopics = res.data.data.list;
    const existingIds = new Set(topicOptions.value.map(item => item.id)); // 已经存在的id
    topicOptions.value = [
        ...topicOptions.value,
        ...newTopics.filter(item => !existingIds.has(item.id)) // 防止重复添加
    ];

    if(topicOptions.value.length <= 10){
        topicScrollHasMore.value = false // 无更多数据
    }
}

// 聚焦时触发
let flag_focus = 0;
const handleTopicFocus = async() => {
    if(flag_focus == 0){
        console.log('获取新的话题列表...')
        // 初始化数据
        // postAddOrUpdateDTO.value.topicIdList = []
        //topicOptions.value = []
        current_Topic.value = 1
        topicScrollHasMore.value = true

        topicLoading.value = true
        await loadTopic()
        topicLoading.value = false

        flag_focus = 1;
    }
}


let scrollHandler = null; // 函数--处理滚动加载
const topicScrollLoading = ref(false) // 滚动加载标识符
const topicScrollHasMore  = ref(true)

// 滚动加载更多
const topicScrollLoadingMore = async()=>{
    if (topicScrollLoading.value || !topicScrollHasMore.value) return;
    console.log('开始加载更多...');
    
    topicScrollLoading.value = true;
    await loadTopic(); // 请求数据
    topicScrollLoading.value = false;
}

// 下拉框出现/隐藏时触发
const visibleChange = (visible : boolean)=>{
	if(visible){
		const popper = document.querySelectorAll('.el-popper .el-select-dropdown__wrap')[1];
        if (popper && !scrollHandler) { // 防止重复添加监听器
            scrollHandler = () => {
                const { scrollTop, scrollHeight, clientHeight } = popper;
                if (scrollTop + clientHeight >= scrollHeight - 50) {
                    topicScrollLoadingMore();
                }
            };
            popper.addEventListener('scroll', scrollHandler);
        }
	}
}



// #endregion


// 表单验证
function validateForm() {
    let isValid = true
    // 验证用户id
    if (!postAddOrUpdateDTO.value.userId) {
        tip_Store.errorTip('用户信息错误，请重新登录！')
        isValid = false
    }
    
    // 验证标题
    if (!postAddOrUpdateDTO.value.title) {
        titleError.value = '请输入标题'
        isValid = false
    } else if (postAddOrUpdateDTO.value.title.length < 2) {
        titleError.value = '标题长度不能少于2个字符'
        isValid = false
    } else {
        titleError.value = ''
    }
    
    // 验证内容
    // if (!postAddOrUpdateDTO.value.content) {
    //     contentError.value = '请输入内容'
    //     isValid = false
    // } else if (postAddOrUpdateDTO.value.content.length < 5) {
    //     contentError.value = '内容长度不能少于5个字符'
    //     isValid = false
    // } else {
    //     contentError.value = ''
    // }
    
    // 验证标签
    if(postAddOrUpdateDTO.value.tagIdList.length < 1){
        tagError.value = '请至少选择1个标签'
        isValid = false
    }else if (postAddOrUpdateDTO.value.tagIdList && postAddOrUpdateDTO.value.tagIdList.length > 5) {
        tagError.value = '最多只能选择5个标签'
        isValid = false
    } else {
        tagError.value = ''
    }
    
    return isValid
}

// 发布
const publishPost =  async ()=> {
    if (!validateForm()) {
        tip_Store.warningTip("请填写完整的信息")
        return
    }
    
    try {
        // 全局加载中，防止用户重复点击
        fullscreenLoading.value = true
        console.log("准备发送的数据为：", postAddOrUpdateDTO.value)

        // 如果是新增
        if(addOrEditFlag.value == 'add'){
            const AddRes = await api.Post_Add(postAddOrUpdateDTO.value)
            if(AddRes.data.code == 1){
                tip_Store.successTip('发布成功')
                cache_Store.reload('Profile', 'index')
                router.go(-1) // 返回上一页
            }else{
                tip_Store.errorTip()
            }
        }

        // 如果是编辑
        if(addOrEditFlag.value == 'edit'){
            const UpdateRes = await api.Post_Update(postAddOrUpdateDTO.value)
            if(UpdateRes.data.code == 1){
                tip_Store.successTip('修改成功')
                cache_Store.reload('Profile', 'index')
                router.go(-1) // 返回上一页
            }else{
                tip_Store.errorTip()
            }
        }
        
        fullscreenLoading.value = false
        
    } catch (error) {
        console.log('发布失败:', error)
        tip_Store.errorTip('未知错误')
    } finally {
        fullscreenLoading.value = false // 解除加载状态
    }
}

// 保存
const save = ()=>{
    alert("保存功能开发中...")
}


const postId_edit = history.state?.postId // 从浏览器历史记录的状态对象（history.state）中安全地获取 postId属性​​
onMounted(async ()=>{
    if(!postId_edit){
        addOrEditFlag.value = 'add' // 新增帖子状态
    }else{
        addOrEditFlag.value = 'edit' // 编辑（修改）帖子状态
        await editPrepareOperation()
    }

})

</script>

<style lang="scss" scoped>

/* #region 头部 */
.header {
    background: white;
    padding: 15px 20px;
    box-shadow: 0 2px 10px rgba(0,0,0,0.1);
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 100;
}

.header-content {
    display: flex;
    align-items: center;
    justify-content: space-between;
}

.header-left {
    display: flex;
    align-items: center;
    gap: 15px;
}

.back-btn {
    font-size: 20px;
    cursor: pointer;
    text-decoration: none;
    color: #333;
    display: flex;
    align-items: center;
}

.header-title {
    font-size: 18px;
    font-weight: 500;
}

.publish-btn {
    padding: 8px 20px;
    background: #ff6b6b;
    color: white;
    border: none;
    border-radius: 20px;
    cursor: pointer;
    font-size: 14px;
}

.publish-btn:disabled {
    background: #ccc;
    cursor: not-allowed;
}
/* #endregion 头部结束 */


/* #region 内容 */
.main-content {
    margin-top: 80px;
    max-width: 800px;
    margin-left: auto;
    margin-right: auto;
    padding: 20px;
}

.publish-form {
    background: white;
    border-radius: 12px;
    padding: 20px;
    box-shadow: 0 2px 12px rgba(0,0,0,0.08);
}

.form-group {
    margin-bottom: 20px;
}

.form-label {
    display: block;
    margin-bottom: 8px;
    font-weight: 500;
    color: #333;
}

.title-input {
    width: 100%;
    padding: 12px 15px;
    border: 1px solid #ddd;
    border-radius: 8px;
    font-size: 14px;
    outline: none;
    transition: border-color 0.3s;
}

.title-input:focus {
    border-color: #ff6b6b;
}

.content-textarea {
    width: 100%;
    min-height: 200px;
    padding: 15px;
    border: 1px solid #ddd;
    border-radius: 8px;
    font-size: 14px;
    line-height: 1.6;
    outline: none;
    resize: vertical;
    font-family: inherit;
    transition: border-color 0.3s;
}

.content-textarea:focus {
    border-color: #ff6b6b;
}


.category-select {
    width: 100%;
    padding: 12px 15px;
    border: 1px solid #ddd;
    border-radius: 8px;
    font-size: 14px;
    outline: none;
    background: white;
    cursor: pointer;
}

.privacy-options {
    display: flex;
    flex-wrap: wrap;
    font-size: 13px;
    gap: 20px;
}

.privacy-option {
    display: flex;
    align-items: center;
    gap: 8px;
    cursor: pointer;
}

.privacy-radio {
    width: 18px;
    height: 18px;
    border: 2px solid #ddd;
    border-radius: 50%;
    position: relative;
    cursor: pointer;
}

.privacy-radio.checked {
    border-color: #ff6b6b;
}

.privacy-radio.checked::after {
    content: '';
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 8px;
    height: 8px;
    background: #ff6b6b;
    border-radius: 50%;
}

.form-actions {
    display: flex;
    gap: 15px;
    justify-content: flex-end;
    margin-top: 30px;
    padding-top: 20px;
    border-top: 1px solid #f0f0f0;
}

.btn-secondary {
    padding: 10px 20px;
    background: white;
    color: #666;
    border: 1px solid #ddd;
    border-radius: 20px;
    cursor: pointer;
    text-align: center;
}

.btn-primary {
    padding: 10px 20px;
    background: #ff6b6b;
    color: white;
    border: none;
    border-radius: 20px;
    cursor: pointer;
    text-align: center;
}

.char-count {
    text-align: right;
    font-size: 12px;
    color: #999;
    margin-top: 5px;
}

.char-count.warning {
    color: #ff6b6b;
}

.error-message {
    color: #ff4d4f;
    font-size: 12px;
    margin-top: 5px;
}
/* #endregion 内容结束 */


/* #region 加载动画样式 */
.circular {
    display: inline;
    height: 30px;
    width: 30px;
    animation: loading-rotate 2s linear infinite;
}
.path {
    animation: loading-dash 1.5s ease-in-out infinite;
    stroke-dasharray: 90, 150;
    stroke-dashoffset: 0;
    stroke-width: 2;
    stroke: var(--el-color-primary);
    stroke-linecap: round;
}
/* #endregion */


/* #region 覆盖elementPlus样式 */
.avatar-uploader .avatar {
  width: 178px;
  height: 178px;
  display: block;
}
:deep(.avatar-uploader .el-upload) {
  border: 1px dashed var(--el-border-color);
  border-radius: 6px;
  cursor: pointer;
  position: relative;
  overflow: hidden;
  transition: var(--el-transition-duration-fast);
}
:deep(.avatar-uploader .el-upload:hover) {
  border-color: var(--el-color-primary);
}
:deep(.el-icon.avatar-uploader-icon) {
  font-size: 28px;
  color: #8c939d;
  width: 178px;
  height: 178px;
  text-align: center;
}


:deep(.el-select__wrapper.is-focused) {
    box-shadow: 0 0 0 1px #ff6b6b inset;
}
.el-select-dropdown__item.is-selected {
    color: #ff6b6b
}
:deep(.el-tag .el-tag__close:hover) {
    background: #f73104;
}
/* #endregion  */
</style>